package com.fy.fyspace.common.utils;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fy.fyspace.constant.ResultMessageConstant;
import com.fy.fyspace.ex.handler.ExceptionHandler;
import com.fy.fyspace.model.vo.picture.ImageMessage;
import lombok.extern.slf4j.Slf4j;
import org.apache.tika.Tika;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.stream.Collectors;

/**
 * 图片文件校验工具类
 */
@Slf4j
public class ImageUtil {


    private static final int CONNECT_TIMEOUT = 5000;
    private static final int READ_TIMEOUT = 5000;

    /**
     * 获取图片主色调
     * @param imageUrl 图片完整URL（包含imageAve参数）
     * @return 返回Web格式的颜色值（#XXXXXX），失败返回null
     */
    public static String getImageMainColor(String imageUrl) {
        if (imageUrl == null || imageUrl.trim().isEmpty()) {
            log.warn("图片URL为空");
            return null;
        }

        // 确保URL包含imageAve参数
        if (!imageUrl.contains("?imageAve")) {
            imageUrl = imageUrl + "?imageAve";
        }

        HttpURLConnection conn = null;
        try {
            // 1. 创建URL对象
            URL url = new URL(imageUrl);

            // 2. 打开连接
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(CONNECT_TIMEOUT);
            conn.setReadTimeout(READ_TIMEOUT);

            // 3. 获取响应码
            int responseCode = conn.getResponseCode();
            log.debug("获取图片颜色 - URL: {}, 响应码: {}", imageUrl, responseCode);

            // 4. 读取响应内容
            if (responseCode == HttpURLConnection.HTTP_OK) {
                try (BufferedReader reader = new BufferedReader(
                        new InputStreamReader(conn.getInputStream()))) {
                    // 读取响应内容
                    String response = reader.lines().collect(Collectors.joining());
                    log.debug("原始响应数据: {}", response);

                    // 解析JSON
                    JSONObject jsonObject = JSONUtil.parseObj(response);
                    String rgb = jsonObject.getStr("RGB");

                    // 转换为Web颜色格式（0xXXXXXX）
                    if (rgb != null && rgb.startsWith("0x")) {
                        String webColor = "0x" + rgb.substring(2);
                        log.debug("颜色转换: {} -> {}", rgb, webColor);
                        return webColor;
                    }
                }
            } else {
                log.error("获取图片颜色失败 - URL: {}, 响应码: {}", imageUrl, responseCode);
            }
            return null;

        } catch (Exception e) {
            log.error("获取图片颜色异常 - URL: {}, 错误: {}", imageUrl, e.getMessage());
            return null;
        } finally {
            // 关闭连接
            if (conn != null) {
                conn.disconnect();
            }
        }
    }

    /**
     * 获取图片主色调（不含imageAve参数的URL）
     * @param imageUrl 图片URL（不含imageAve参数）
     * @return 返回Web格式的颜色值（#XXXXXX），失败返回null
     */
    public static String getImageMainColorWithoutParam(String imageUrl) {
        if (imageUrl == null || imageUrl.trim().isEmpty()) {
            return null;
        }
        return getImageMainColor(imageUrl + "?imageAve");
    }

    /**
     * 标准化颜色格式
     * @param color 输入的颜色值（0xXXXXXX 或 XXXXXX）
     * @return 标准的Web颜色格式（#XXXXXX）
     */
    public static String standardizeColorFormat(String color) {
        if (color == null || color.trim().isEmpty()) {
            return null;
        }

        // 移除所有非十六进制字符
        String processedColor = color.replaceAll("[^0-9A-Fa-f]", "");

        // 处理0x前缀
        if (color.contains("0x")) {
            processedColor = processedColor.substring(processedColor.indexOf("0x") + 2);
        }

        // 确保是6位
        if (processedColor.length() >= 6) {
            // 取后6位
            processedColor = processedColor.substring(processedColor.length() - 6);
            return "#" + processedColor.toLowerCase();
        }

        return null;
    }

    /**
     * 默认最大文件大小 (2MB)
     */
    private static final long DEFAULT_MAX_SIZE = 2 * 1024 * 1024;

    private ImageUtil() {}

    /**
     * 校验图片文件
     *
     * @param file
     * @return
     */
    public static void validate(MultipartFile file) {

        String originalFilename = null;
        // 2. 获取原始文件名
        if (StrUtil.isNotBlank(file.getOriginalFilename())) {
            originalFilename = file.getOriginalFilename();
        }

        // 3. 校验文件大小
        long fileSize = file.getSize();
        ExceptionHandler.throwIf(fileSize <= 0
                || file == null
                || file.isEmpty()
                || originalFilename == null,
                ResultMessageConstant.PARAMS_ERROR);

        // 4. 使用Tika检测文件类型
        String mimeType;
        try {
            Tika tika = new Tika();
            mimeType = tika.detect(file.getInputStream());

            // 校验是否为图片类型
            ExceptionHandler.throwIf(!mimeType.startsWith("image/"), ResultMessageConstant.PARAMS_ERROR);
        } catch (IOException e) {
            log.error("文件类型检测失败", e);
            ExceptionHandler.throwIf(true, ResultMessageConstant.SYSTEM_ERROR);
        }
    }

    /**
     * 获取图片信息
     *
     * @param file 图片文件
     * @return 图片信息对象
     */
    public static ImageMessage getImageMessage(MultipartFile file) throws IOException {
        BufferedImage image = ImageIO.read(file.getInputStream());
        if (image == null) {
            throw new IOException("无效的图片文件");
        }

        ImageMessage imageMessage = new ImageMessage();
        imageMessage.setPicWidth(image.getWidth());
        imageMessage.setPicHeight(image.getHeight());
        imageMessage.setPicScale((double) image.getWidth() / image.getHeight());
        imageMessage.setPicSize(file.getSize());
        imageMessage.setPicFormat(getImageFormat(file.getOriginalFilename()));

        return imageMessage;
    }

    /**
     * 从消息构建图片信息
     */
    public static ImageMessage getImageMessage(Long size, Integer width, Integer height,
            Double scale, String format) {
        ImageMessage imageMessage = new ImageMessage();
        imageMessage.setPicWidth(width);
        imageMessage.setPicHeight(height);
        imageMessage.setPicScale(scale);
        imageMessage.setPicSize(size);
        imageMessage.setPicFormat(format);
        return imageMessage;
    }

    /**
     * 获取图片格式
     */
    private static String getImageFormat(String fileName) {
        String format = "jpg";
        if (fileName != null) {
            int lastDotIndex = fileName.lastIndexOf('.');
            if (lastDotIndex > 0) {
                format = fileName.substring(lastDotIndex + 1).toLowerCase();
            }
        }
        return format;
    }

    /**
     * 从URL下载图片
     *
     * @param imageUrl 图片URL
     * @return 图片字节数组
     */
    public static byte[] downloadImageFromUrl(String imageUrl) {
        int maxRetries = 3;
        int currentRetry = 0;
        int timeout = 60000; // 60秒超时

        while (currentRetry < maxRetries) {
            try {
                URL url = new URL(imageUrl);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(timeout);
                conn.setReadTimeout(timeout);
                conn.setRequestProperty("User-Agent", "Mozilla/5.0");

                // 检查响应码
                int responseCode = conn.getResponseCode();
                if (responseCode != HttpURLConnection.HTTP_OK) {
                    throw new IOException("Server returned HTTP response code: " + responseCode);
                }

                // 获取内容长度
                int contentLength = conn.getContentLength();
                if (contentLength <= 0) {
                    throw new IOException("Invalid content length: " + contentLength);
                }

                // 使用带缓冲的流来提高性能
                try (InputStream in = new BufferedInputStream(conn.getInputStream());
                        ByteArrayOutputStream out = new ByteArrayOutputStream()) {
                    byte[] buffer = new byte[8192];
                    int bytesRead;
                    while ((bytesRead = in.read(buffer)) != -1) {
                        out.write(buffer, 0, bytesRead);
                    }
                    byte[] imageData = out.toByteArray();

                    // 验证下载的数据
                    if (imageData.length == 0) {
                        throw new IOException("Downloaded image data is empty");
                    }

                    log.info("Successfully downloaded image from URL: {}, size: {} bytes", imageUrl, imageData.length);
                    return imageData;
                }
            } catch (Exception e) {
                currentRetry++;
                if (currentRetry == maxRetries) {
                    log.error("Failed to download image after {} retries: {}", maxRetries, imageUrl, e);
                    throw new RuntimeException("下载图片失败", e);
                }
                log.warn("Retry {} downloading image from URL: {}", currentRetry, imageUrl);
                try {
                    // 指数退避策略
                    Thread.sleep(1000L * currentRetry * currentRetry);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("Download interrupted", ie);
                }
            }
        }
        throw new RuntimeException("下载图片失败: 超过最大重试次数");
    }

    /**
     * 将图片转换为WebP格式
     *
     * @param inputFile 输入文件
     * @param quality   压缩质量 (0-100)
     * @return WebP格式的字节数组
     */
    public static byte[] convertToWebP(File inputFile, int quality) {
        try {
            // 读取原始图片
            BufferedImage image = ImageIO.read(inputFile);
            if (image == null) {
                throw new IllegalArgumentException("无效的图片文件");
            }

            // 创建临时文件用于存储WebP
            File tempWebpFile = File.createTempFile("temp", ".webp");

            try (FileImageOutputStream output = new FileImageOutputStream(tempWebpFile)) {
                // 获取WebP writer
                ImageWriter writer = ImageIO.getImageWritersByMIMEType("image/webp").next();
                writer.setOutput(output);

                // 设置压缩参数
                javax.imageio.ImageWriteParam writeParam = writer.getDefaultWriteParam();
                writeParam.setCompressionMode(javax.imageio.ImageWriteParam.MODE_EXPLICIT);
                writeParam.setCompressionType("Lossy"); // 设置压缩类型为有损压缩
                writeParam.setCompressionQuality(quality / 100f); // 将quality转换为0-1之间的值

                // 使用设置的质量参数写入图片
                writer.write(null, new IIOImage(image, null, null), writeParam);

                // 读取WebP文件内容
                byte[] webpBytes = IoUtil.readBytes(new FileInputStream(tempWebpFile));

                // 清理临时文件
                tempWebpFile.delete();

                return webpBytes;
            }
        } catch (Exception e) {
            log.error("WebP转换失败", e);
            throw new RuntimeException("WebP转换失败", e);
        }
    }

    /**
     * 估算WebP转换后的文件大小
     *
     * @param originalSize 原始文件大小（字节）
     * @return 预估的WebP文件大小（字节）
     */
    public static long estimateWebPSize(long originalSize) {
        // WebP通常可以节省25-34%的空间，这里取保守估计25%
        return (long) (originalSize * 0.75);
    }

    /**
     * 获取标准颜色（将数据万象的 5 位色值转为 6 位）
     *
     * @param color
     * @return
     */
    public static String getStandardColor(String color) {
        // 每一种 rgb 色值都有可能只有一个 0，要转换为 00)
        // 如果是六位，不用转换，如果是五位，要给第三位后面加个 0
        // 示例：
        // 0x080e0 => 0x0800e
        if (color.length() == 7) {
            color = color.substring(0, 4) + "0" + color.substring(4, 7);
        }
        return color;
    }

    /**
     * 计算两个颜色的相似度
     *
     * @param color1 第一个颜色
     * @param color2 第二个颜色
     * @return 相似度（0到1之间，1为完全相同）
     */
    public static double calculateSimilarity(Color color1, Color color2) {
        int r1 = color1.getRed();
        int g1 = color1.getGreen();
        int b1 = color1.getBlue();

        int r2 = color2.getRed();
        int g2 = color2.getGreen();
        int b2 = color2.getBlue();

        // 计算欧氏距离
        double distance = Math.sqrt(Math.pow(r1 - r2, 2) + Math.pow(g1 - g2, 2) + Math.pow(b1 - b2, 2));

        // 计算相似度
        return 1 - distance / Math.sqrt(3 * Math.pow(255, 2));
    }

    /**
     * 根据十六进制颜色代码计算相似度
     *
     * @param hexColor1 第一个颜色的十六进制代码（如 0xFF0000）
     * @param hexColor2 第二个颜色的十六进制代码（如 0xFE0101）
     * @return 相似度（0到1之间，1为完全相同）
     */
    public static double calculateSimilarity(String hexColor1, String hexColor2) {
        Color color1 = Color.decode(hexColor1);
        Color color2 = Color.decode(hexColor2);
        return calculateSimilarity(color1, color2);
    }
}